Fondamentaux “ base”

Les data.frame

data.frame

L’une des classes S3 importante dans est la classe data.frame (tibble dans le “tidyverse”), qui repose entièrement sur les listes.

Qu’est-ce qu’un data.frame ?
Un data.frame est une liste nommée, de vecteur de même dimension (longueur) avec des attributs names (noms des colonnes) et row.names.

df1 <- data.frame(x = 1:3, y = letters[1:3])
typeof(df1)
#> [1] "list"

data.frame

L’une des classes S3 importante dans est la classe data.frame (tibble dans le “tidyverse”), qui repose entièrement sur les listes.

Qu’est-ce qu’un data.frame ?
Un data.frame est une liste nommée, de vecteur de même longueur avec des attributs names (noms des colonnes) et row.names.

attributes(df1)
#> $names
#> [1] "x" "y"
#> 
#> $class
#> [1] "data.frame"
#> 
#> $row.names
#> [1] 1 2 3

data.frame

Un data.frame a donc une structure rectangulaire et dispose de noms pour les lignes et les colonnes.

  • rownames() pour obtenir le noms des lignes.
  • colnames() (ou names()) pour obtenir le noms des colonnes.
  • nrow() pour obtenir le nombre de lignes.
  • ncol() (ou length()) pour obtenir le nombre de colonnes.

data.frame

La création d’un data.frame se fait via data.frame().

df <- data.frame(
  x = 1:3, 
  y = c("a", "b", "c")
)
str(df)
#> 'data.frame':    3 obs. of  2 variables:
#>  $ x: int  1 2 3
#>  $ y: chr  "a" "b" "c"

data.frame

La création d’un data.frame se fait via data.frame().

df <- data.frame(
  x = 1:3, 
  y = c("a", "b", "c"),
  stringsAsFactors = TRUE # Par défaut dans R < 4.0
)
str(df)
#> 'data.frame':    3 obs. of  2 variables:
#>  $ x: int  1 2 3
#>  $ y: Factor w/ 3 levels "a","b","c": 1 2 3

data.frame

La création d’un data.frame se fait via data.frame().

df <- data.frame(
  x = 1:3, 
  y = c("a", "b", "c"),
  stringsAsFactors = FALSE # Par défaut dans R > 4.0
)
str(df)
#> 'data.frame':    3 obs. of  2 variables:
#>  $ x: int  1 2 3
#>  $ y: chr  "a" "b" "c"

data.frame

Par défaut, un data.frame requiert des noms de colonnes syntaxiquement correct.

names(data.frame(`1` = 1))
#> [1] "X1"
names(data.frame(`1` = 1, check.names = FALSE))
#> [1] "1"

data.frame

Un data.frame requiert que ces éléments soit de même longueur, quand cela n’est pas respecté et lorsque c’est possible, les valeurs des vecteurs les plus courts sont recyclés.

data.frame(x = 1:4, y = 1:2)
#>   x y
#> 1 1 1
#> 2 2 2
#> 3 3 1
#> 4 4 2
data.frame(x = 1:4, y = 1:3)
#> Error in data.frame(x = 1:4, y = 1:3): arguments imply differing number of rows: 4, 3

data.frame

Les data.frame ayant des noms de lignes, il est possible de les définir de plusieurs façons.

df3 <- data.frame(
  age = c(35, 27, 18),
  hair = c("blond", "brown", "black"),
  row.names = c("Bob", "Susan", "Sam")
)
df3
#>       age  hair
#> Bob    35 blond
#> Susan  27 brown
#> Sam    18 black

data.frame

Les data.frame ayant des noms de lignes, il est possible de les définir de plusieurs façons.

df3 <- data.frame(
  age = c(35, 27, 18),
  hair = c("blond", "brown", "black")
)
rownames(df3) <- c("Bob", "Susan", "Sam")
df3
#>       age  hair
#> Bob    35 blond
#> Susan  27 brown
#> Sam    18 black

data.frame

L’usage des noms de lignes n’est pas recommandé.

  • Le nom des lignes est une donnée, pourquoi la stocker différemment ?

  • Le nom des lignes doit obligatoirement être une chaîne de caractères.

  • Chaque nom de ligne doit-être unique. s’assurera que ce soit le cas !

    df3[c(1, 1, 1), ]
    #>       age  hair
    #> Bob    35 blond
    #> Bob.1  35 blond
    #> Bob.2  35 blond

Test et Conversion de Type

is.data.frame() permet de tester si l’objet est un data.frame() quand as.data.frame() permet la conversion.

is.data.frame(df1)
#> [1] TRUE

Exercises

  1. Est-il possible d’avoir un data.frame avec zéro lignes ? Et zéro colonnes ?

  2. Que se passe-t-il lorsque des noms lignes avec duplicatas sont définis via rownames() ?

  3. Que donne t(df) ou t(t(df)) ? Avec, df un objet de classe data.frame.

  4. Que fait as.matrix() sur un data.frame dont les colonnes sont de type différents ?

NULL

NULL un objet particulier.

typeof(NULL)
#> [1] "NULL"
length(NULL)
#> [1] 0
x <- NULL
attr(x, "y") <- 1
#> Error in attr(x, "y") <- 1: attempt to set an attribute on NULL

NULL

Il est possible de tester le caractère NULL d’un objet.

is.null(NULL)
#> [1] TRUE

NULL sert à définir :

  • un vecteur vide (p.ex., c().

  • un vecteur absent (p.ex., argument non défini d’une fonction).

Fondamentaux “ base”

Sélection

Sélection Dans un Vecteur

  • Entier positif.
x <- c(2.1, 4.2, 3.3, 5.4)
x[c(3, 1)]
#> [1] 3.3 2.1
x[c(1, 1)]
#> [1] 2.1 2.1
x[c(2.1, 2.9)] # Troncature
#> [1] 4.2 4.2

Sélection Dans un Vecteur

  • Entier négatif.
x <- c(2.1, 4.2, 3.3, 5.4)
x[-c(3, 1)]
#> [1] 4.2 5.4
x[c(-1, 2)] # Pas de mélange
#> Error in x[c(-1, 2)]: only 0's may be mixed with negative subscripts

Sélection Dans un Vecteur

  • Booléen.
x <- c(2.1, 4.2, 3.3, 5.4)
x[c(TRUE, TRUE, FALSE, FALSE)]
#> [1] 2.1 4.2
x[x > 3]
#> [1] 4.2 3.3 5.4

Sélection Dans un Vecteur

  • Recyclage des valeurs.
x <- c(2.1, 4.2, 3.3, 5.4)
x[c(TRUE, FALSE)] # Recyclage
#> [1] 2.1 3.3
x[c(TRUE, FALSE, TRUE, FALSE)]
#> [1] 2.1 3.3

Sélection Dans un Vecteur

  • Valeur manquante.
x <- c(2.1, 4.2, 3.3, 5.4)
x[c(TRUE, TRUE, NA, FALSE)]
#> [1] 2.1 4.2  NA

Sélection Dans un Vecteur

  • “Rien”.
x <- c(2.1, 4.2, 3.3, 5.4)
x[]
#> [1] 2.1 4.2 3.3 5.4

Sélection Dans un Vecteur

  • Zéro.
x <- c(2.1, 4.2, 3.3, 5.4)
x[0]
#> numeric(0)

Sélection Dans un Vecteur

  • Avec des “noms”.
x <- c(2.1, 4.2, 3.3, 5.4)
names(x) <- letters[1:4]
x[c("d", "c", "a")]
#>   d   c   a 
#> 5.4 3.3 2.1
x[c("a", "a", "a")]
#>   a   a   a 
#> 2.1 2.1 2.1

Sélection Dans un Vecteur

  • Avec des “noms”, une correspondance parfaite est requise.
z <- c(abc = 1, def = 2)
z[c("a", "d")] # Correspondance parfaite
#> <NA> <NA> 
#>   NA   NA
z[c("abc", "def")] 
#> abc def 
#>   1   2

Sélection Dans une Liste

La sélection s’opère de la même façon que sur un vecteur.

  • [, renvoi une liste.
  • [[ et $, renvoient un élément d’une liste.

Sélection Dans une Liste

La sélection s’opère de la même façon que sur un vecteur.

  • [, renvoi une liste.

    x <- list(2.1, 4.2, 3.3, 5.4)
    x[c(1, 3)]
    #> [[1]]
    #> [1] 2.1
    #> 
    #> [[2]]
    #> [1] 3.3
    x[[2]]
    #> [1] 4.2

Sélection Dans une Liste

La sélection s’opère de la même façon que sur un vecteur.

  • [[ et $, renvoient un élément d’une liste.

    x <- list(2.1, 4.2, 3.3, 5.4)
    names(x) <- letters[1:4]
    x$a
    #> [1] 2.1
    x[["b"]]
    #> [1] 4.2

Sélection Dans une Matrice our Array

La sélection peut s’effectuer avec un vecteur, plusieurs vecteurs ou une matrice.

a <- matrix(1:9, nrow = 3)
colnames(a) <- c("A", "B", "C")
a[1:2, ]
#>      A B C
#> [1,] 1 4 7
#> [2,] 2 5 8
a[c(TRUE, FALSE, TRUE), c("B", "A")]
#>      B A
#> [1,] 4 1
#> [2,] 6 3

Sélection Dans une Matrice our Array

Comme les matrices ou arrays ne sont que des vecteurs avec un attribut dim, la sélection peut se faire directement avec un seul vecteur de position.

vals <- outer(1:5, 1:5, FUN = "paste", sep = ",")
vals
#>      [,1]  [,2]  [,3]  [,4]  [,5] 
#> [1,] "1,1" "1,2" "1,3" "1,4" "1,5"
#> [2,] "2,1" "2,2" "2,3" "2,4" "2,5"
#> [3,] "3,1" "3,2" "3,3" "3,4" "3,5"
#> [4,] "4,1" "4,2" "4,3" "4,4" "4,5"
#> [5,] "5,1" "5,2" "5,3" "5,4" "5,5"
vals[c(4, 15)]
#> [1] "4,1" "5,3"

Sélection Dans une Matrice our Array

Il est également possible d’effectuer la sélection à partir d’une matrice donnant la position des dans chacune des dimensions de la matrice ou array que l’on souhaite manipuler.

vals <- outer(1:5, 1:5, FUN = "paste", sep = ",")
select <- matrix(ncol = 2, byrow = TRUE, c(
  1, 1,
  3, 1,
  2, 4
))
vals[select]
#> [1] "1,1" "3,1" "2,4"

Sélection Dans un data.frame

Les data.frame se comportent comme des listes et comme des matrices.

df <- data.frame(x = 1:3, y = 3:1, z = letters[1:3])
df[df$x == 2, ]
#>   x y z
#> 2 2 2 b
df[c(1, 3), ]
#>   x y z
#> 1 1 3 a
#> 3 3 1 c

Sélection Dans un data.frame

Deux approches pour sélectionner les colonnes d’un data.frame.

df <- data.frame(x = 1:3, y = 3:1, z = letters[1:3])
df[c("x", "z")] # approche liste
#>   x z
#> 1 1 a
#> 2 2 b
#> 3 3 c
df[, c("x", "z")] # approche matrice
#>   x z
#> 1 1 a
#> 2 2 b
#> 3 3 c

Sélection Dans un data.frame

Attention, ces deux approches ne sont pas tout à fait équivalentes.

str(df["x"])
#> 'data.frame':    3 obs. of  1 variable:
#>  $ x: int  1 2 3
str(df[, "x"])
#>  int [1:3] 1 2 3
str(df[, "x", drop = FALSE])
#> 'data.frame':    3 obs. of  1 variable:
#>  $ x: int  1 2 3

Exercices

  1. Corriger les erreurs dans les codes suivants.

    mtcars[mtcars$cyl = 4, ]
    mtcars[-1:4, ]
    mtcars[mtcars$cyl <= 5]
    mtcars[mtcars$cyl == 4 | 6, ]
  2. Pourquoi le code suivant renvoi cinq valeurs manquantes ? Et avec x[NA_real_] ?

x <- 1:5
x[NA]
#> [1] NA NA NA NA NA

Exercices

  1. Pourquoi mtcars[1:20] produit une erreur alors que mtcars[1:20, ] fonctionne ? Quelle est la différence ?

  2. Que fait df[is.na(df)] <- 0 ? Sur quel principe repose cette commande ?

Les Opérateurs [[ et $

[[ renvoi toujours un élément plus petit.

x <- list(1:3, "a", 4:6)
x[1]
#> [[1]]
#> [1] 1 2 3
x[[1]]
#> [1] 1 2 3

Les Opérateurs [[ et $

$ fonctionne d’une façon proche de celle de [[.

mitcars$cyl
mitcars[["cyl"]]

Les Opérateurs [[ et $

Le $ n’est pas utilisable lorsque le nom de la colonne ou de l’élément est stockée dans une variable.

var <- "cyl"
mtcars$var
#> NULL
mtcars[[var]]
#>  [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4

Les Opérateurs [[ et $

L’opérateur $ permet également une correspondance partiel des noms, contrairement à [[ (ou [).

x <- list(abc = 1)
x$a
#> [1] 1
x[["a"]]
#> NULL

Les Opérateurs slot() et @

Les opérateurs slot() et @ sont des opérateurs spécifiques des objets de classe S4, ou slot() correspond à [[ et @ à $.

Exercices

  1. Extraire la troisième valeur de la variable cyl du jeu de données mtcars.

  2. À partir de la régression linéaire mod <- lm(mpg ~ wt, data = mtcars), extraire le nombre de degré de liberté. Puis extraire, le R carré du modèle (summary(mod)).

Sélection et Affectation

Les opérateurs [, [[ et $ permettent également les affectations ou modifications.

x <- 1:5
x[c(1, 2)] <- c(101, 102)
x
#> [1] 101 102   3   4   5

Attention au recyclage des valeurs !

Sélection et Affectation

Approche identique pour les listes.

x <- list(a = 1, b = 2)
x[["b"]] <- NULL
y <- list(a = 1, b = 2)
y["b"] <- list(NULL)
str(y)
#> List of 2
#>  $ a: num 1
#>  $ b: NULL

Sélection et Affectation

Le cas de la sélection par “rien”, c’est-à-dire, df[], permet dans le cas d’une affectation de préservé la structure d’origine.

mtcars[] <- lapply(mtcars, as.integer)
is.data.frame(mtcars)
#> [1] TRUE
mtcars <- lapply(mtcars, as.integer)
is.data.frame(mtcars)
#> [1] FALSE

Exercices

  1. Ajouter une colonne cyl_fct à mtcars comme une copie de la colonne cyl. Quel est le type de la nouvelle colonne ? Modifier le type de cette colonne dans un type plus approprié pour une analyse de comparaison de groupes défini par cyl_fct.

  2. Reprendre les fonctions vu au préalable et identifier la structure, le type, la classe et les attributs des objets générés par ces fonctions, p.ex., stats::lm(), stats::aov(), t.test(), ggplot2::ggplot(), etc.

  3. Manipuler les fonctions str(), typeof(), dput(), attributes(), attr(), dimnames(), dim(), rownames(), colnames() et names() sur les jeux de données de datasets (ls(name = "package:datasets")).

  4. Créer une liste, un vecteur, un data.frame à l’aide de la fonction structure().

Fondamentaux “ base”

Les Fonctions

Les Fonctions

Une fonction se décompose en trois éléments :

  • Les arguments (arguments).
  • Le corps (body).
  • L’environnement (environment).

Les Fonctions

f <- function(x, y) {
  # Commentaire
  return(x + y)
}
f <- function(x, y) {
  # Commentaire
  x + y
}

Les Fonctions

formals(f)
#> $x
#> 
#> 
#> $y
body(f)
#> {
#>     x + y
#> }
environment(f)
#> <environment: 0x563d9bdf5e98>

Les Fonctions

Les fonctions sont des objets au même titre que les vecteurs.

attributes(f)
#> $srcref
#> function(x, y) {
#>   # Commentaire
#>   x + y
#> }

Les Fonctions

  • Fonction “classique”, affectée d’un nom.
f <- function(x, y) {
  # Commentaire
  x + y
}
f(1, 2)
#> [1] 3
  • Fonction anonyme.
(function(x, y) x + y)(1, 2)
#> [1] 3

Les Fonctions Composées

square <- function(x) x^2
deviation <- function(x) x - mean(x)
x <- runif(100)

Les Fonctions Composées

Imbrication

sqrt(mean(square(deviation(x))))
#> [1] 0.2808312

Les Fonctions Composées

Séquentiel

out <- deviation(x)
out <- square(out)
out <- mean(out)
out <- sqrt(out)
out
#> [1] 0.2808312

Les Fonctions Composées

“Pipe” %>% (magrittr)

library(magrittr)
x %>%
  deviation() %>%
  square() %>%
  mean() %>%
  sqrt()
#> [1] 0.2808312

Exercices

  1. match.fun() permet de trouver une fonction avec son nom. À partir d’une fonction, est-il possible de trouver son nom ?

  2. Quelles fonctions permettraient d’identifier si un objet est une fonction et s’il s’agit d’une primitive ? Par exemple, +, sum, lm et t.test.

  3. Quelles sont les composantes d’une fonction ?